package com.zhangmeng.tools.utils;


import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.x509.X509V3CertificateGenerator;

import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;

/**
 * @author : 芊芊墨客
 * @version : 1.0
 * @date : 2023-04-23 09:17
 */
@Slf4j
public class JksUtils {

    public static class GetCertFile {

        //证书颁发者
        static String CertificateIssuer = "C=中国,ST=广东,L=广州,O=人民组织,OU=人民单位,CN=人民颁发";
        //证书使用者
        static String CertificateUser = "C=中国,ST=广东,L=广州,O=人民组织,OU=人民单位,CN=";

        public static String x509Certificate(String dir){
            Path path = Paths.get(dir + file_name() + ".cer");
            try {
                if (!Files.exists(path)){
                    Files.createFile(path);
                }
                X509Certificate cert = getCert(path.toFile());
                return cert.toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        public static String file_name(){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
            return sdf.format(new Date());
        }

        /*
         * CN(Common Name名字与姓氏)
         * OU(Organization Unit组织单位名称)
         * O(Organization组织名称)
         * ST(State州或省份名称)
         * C(Country国家名称)
         * L(Locality城市或区域名称)
         *
         * "F:\\cer.cer"
         * */
        public static X509Certificate getCert(File file) throws Exception {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            X509V3CertificateGenerator x509V3CertificateGenerator = new X509V3CertificateGenerator();
            //设置证书序列号
            x509V3CertificateGenerator.setSerialNumber(BigInteger.TEN);
            //设置证书颁发者
            x509V3CertificateGenerator.setIssuerDN(new X500Principal(CertificateIssuer));
            //设置证书使用者
            x509V3CertificateGenerator.setSubjectDN(new X500Principal(CertificateUser + "sun"));
            //设置证书有效期
            x509V3CertificateGenerator.setNotAfter(new Date(System.currentTimeMillis() + 1000 * 365 * 24 * 3600));
            x509V3CertificateGenerator.setNotBefore(new Date(System.currentTimeMillis()));
            //设置证书签名算法
            x509V3CertificateGenerator.setSignatureAlgorithm("SHA1withRSA");

            x509V3CertificateGenerator.setPublicKey(publicKey);

            //临时bc方法添加都环境变量
            Security.addProvider(new BouncyCastleProvider());
            X509Certificate x509Certificate = x509V3CertificateGenerator.generateX509Certificate(keyPair.getPrivate(), "BC");
            //写入文件
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(x509Certificate.getEncoded());
            fos.flush();
            fos.close();
            return x509Certificate;
        }
    }

    public static class GetJksAndCerFile {

        public static void jks_cer(String file,String keypass,String storepass,String cer_file) {
            buildKeyAndSaveToJksFile(file, keypass, storepass);
            exportCerFile(file,cer_file);
//            try {
//                readJks(file,keypass);
//                readCer(cer_file);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
        }

        public static void executeCommand(String[] arstringCommand) {
            try {
                Runtime.getRuntime().exec(arstringCommand);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }

        /**
         *
         * @param file //f:/demo.jks
         * @param keypass 123456
         * @param storepass 123456
         */
        //生成密钥并保存到jks文件
        public static void buildKeyAndSaveToJksFile(String file,String keypass,String storepass) {
            String[] command = new String[]{
                    "cmd ",
                    "/k",
                    "start", // cmd Shell命令
                    "keytool", "-genkeypair", //表示生成密钥
                    "-alias", //要处理的条目的别名（jks文件别名）
                    "sun",
                    "-keyalg", //密钥算法名称(如 RSA DSA（默认是DSA）)
                    "RSA",
                    "-keysize",//密钥位大小(长度)
                    "1024",
                    "-sigalg", //签名算法名称
                    "SHA1withRSA",
                    "-dname",// 唯一判别名,CN=(名字与姓氏), OU=(组织单位名称), O=(组织名称), L=(城市或区域名称),
                    // ST=(州或省份名称), C=(单位的两字母国家代码)"
                    "CN=(张三), OU=(人民单位), O=(人民组织), L=(广州), ST=(广东), C=(中国)",
                    "-validity", // 有效天数
                    "36500",
                    "-keypass",// 密钥口令(私钥的密码)
                    keypass,
                    "-keystore", //密钥库名称(jks文件路径)
                    file,
                    "-storepass", // 密钥库口令(jks文件的密码)
                    storepass,
                    "-v"// 详细输出（秘钥库中证书的详细信息）
            };
            executeCommand(command);
        }


        //从jks文件中导出证书文件
        public static void exportCerFile(String jks_file,String cer_file) {
            String[] command = new String[]{
                    "cmd ", "/k",
                    "start", // cmd Shell命令

                    "keytool",
                    "-exportcert", // - export指定为导出操作
                    "-alias", // -alias指定别名，这里是ss
                    "sun",
                    "-keystore", // -keystore指定keystore文件，这里是d:/demo.keystore
                    jks_file,
                    "-rfc",
                    "-file",//-file指向导出路径
                    cer_file,
                    "-storepass",// 指定密钥库的密码
                    "123456"
            };
            executeCommand(command);
        }

        public static class JKSInfo{
            private String private_key;
            private String public_key;

            public String getPrivate_key() {
                return private_key;
            }

            public void setPrivate_key(String private_key) {
                this.private_key = private_key;
            }

            public String getPublic_key() {
                return public_key;
            }

            public void setPublic_key(String public_key) {
                this.public_key = public_key;
            }
        }

        //读取jks文件获取公、私钥
        public static void readJks(String file,String keypass) throws Exception {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(new FileInputStream(file), keypass.toCharArray());
            Enumeration<String> aliases = keyStore.aliases();
            String alias = null;
            while (aliases.hasMoreElements()) {
                alias = aliases.nextElement();
            }
            log.info("jks文件别名是：" + alias);
            PrivateKey key = (PrivateKey) keyStore.getKey(alias, "123456".toCharArray());
            System.out.println("jks文件中的私钥是：" + new String(Base64.encode(key.getEncoded())));
            Certificate certificate = keyStore.getCertificate(alias);
            PublicKey publicKey = certificate.getPublicKey();
            log.info("jks文件中的公钥:" + new String(Base64.encode(publicKey.getEncoded())));
        }


        //读取证书文件获取公钥
        public static void readCer(String file) throws Exception {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(file));
            PublicKey publicKey = certificate.getPublicKey();
           log.info("证书中的公钥:" + new String(Base64.encode(publicKey.getEncoded())));
        }
    }
}
